home *** CD-ROM | disk | FTP | other *** search
/ Collection of Tools & Utilities / Collection of Tools and Utilities.iso / system / devlod.zip / DEVLOD.C < prev    next >
C/C++ Source or Header  |  1990-09-25  |  13KB  |  358 lines

  1. /********************************************************************
  2.  *     DEVLOD.C - Jim Kyle - 08/20/90                               *
  3.  *            Copyright 1990 by Jim Kyle - All Rights Reserved      *
  4.  *     (minor revisions by Andrew Schulman - 9/12/90                *
  5.  *     Dynamic loader for device drivers                            *
  6.  *            Requires Turbo C; see DEVLOD.MAK also for ASM helpers.*
  7.  ********************************************************************/
  8.      
  9. #include <stdio.h>
  10. #include <stdlib.h>
  11. #include <dos.h>
  12.  
  13. typedef unsigned char BYTE;
  14.  
  15. #define GETFLAGS __emit__(0x9F)     /* if any error, quit right now */
  16. #define FIXDS    __emit__(0x16,0x1F)/* PUSH SS, POP DS              */
  17. #define PUSH_BP  __emit__(0x55)
  18. #define POP_BP   __emit__(0x5D)
  19.  
  20. unsigned _stklen = 0x200;
  21. unsigned _heaplen = 0;
  22.  
  23. char FileName[65];  /* filename global buffer                       */
  24. char * dvrarg;      /* points to char after name in cmdline buffer  */
  25. unsigned movsize;   /* number of bytes to be moved up for driver    */
  26. void (far * driver)();  /* used as pointer to call driver code      */
  27. void far * drvptr;  /* holds pointer to device driver               */
  28. void far * nuldrvr; /* additional driver pointers                   */
  29. void far * nxtdrvr;
  30. BYTE far * nblkdrs; /* points to block device count in List of Lists*/
  31. unsigned lastdrive; /* value of LASTDRIVE in List of Lists          */
  32. BYTE far * CDSbase; /* base of Current Dir Structure                */
  33. int CDSsize;        /* size of CDS element                          */
  34. unsigned nulseg;    /* hold parts of ListOfLists pointer            */
  35. unsigned nulofs;
  36. unsigned LoLofs;
  37.  
  38. #pragma pack(1)
  39.  
  40. struct packet{      /* device driver's command packet               */
  41.     BYTE hdrlen;
  42.     BYTE unit;
  43.     BYTE command;       /* 0 to initialize      */
  44.     unsigned status;    /* 0x8000 is error      */
  45.     BYTE reserv[8];
  46.     BYTE nunits;
  47.     unsigned brkofs;    /* break adr on return  */
  48.     unsigned brkseg;    /* break seg on return  */
  49.     unsigned inpofs;    /* SI on input          */
  50.     unsigned inpseg;    /* _psp on input        */
  51.     BYTE NextDrv;       /* next available drive */
  52.   } CmdPkt;
  53.   
  54. typedef struct {    /* Current Directory Structure (CDS)            */
  55.     BYTE path[0x43];
  56.     unsigned flags;
  57.     void far *dpb;
  58.     unsigned start_cluster;
  59.     unsigned long ffff;
  60.     unsigned slash_offset;  /* offset of '\' in current path field  */
  61.     // next for DOS4+ only
  62.     BYTE unknown;
  63.     void far *ifs;
  64.     unsigned unknown2;
  65.     } CDS;
  66.  
  67. extern unsigned _psp;       /* established by startup code in c0    */
  68. extern unsigned _heaptop;   /* established by startup code in c0    */
  69. extern BYTE _osmajor;       /* established by startup code      */
  70. extern BYTE _osminor;       /* established by startup code      */
  71.  
  72. void _exit( int );          /* established by startup code in c0    */
  73. void abort( void );         /* established by startup code in c0    */
  74.  
  75. void movup( char far *, char far *, int ); /* in MOVUP.ASM file     */
  76. void copyptr( void far *src, void far *dst ); /* in MOVUP.ASM file  */
  77.  
  78. void exit(int c)            /* called by startup code's sequence    */
  79. { _exit(c);}
  80.  
  81. int Get_Driver_Name ( void )
  82. { char *nameptr;
  83.   int i, j, cmdlinesz;
  84.  
  85.   nameptr = (char *)0x80;   /* check command line for driver name   */
  86.   cmdlinesz = (unsigned)*nameptr++;
  87.   if (cmdlinesz < 1)        /* if nothing there, return FALSE       */
  88.     return 0;
  89.   for (i=0; i<cmdlinesz && nameptr[i]<'!'; i++) /* skip blanks      */
  90.     ;
  91.   dvrarg = (char *)&nameptr[i]; /* save to put in SI                */
  92.   for ( j=0; i<cmdlinesz && nameptr[i]>' '; i++)    /* copy name    */
  93.     FileName[j++] = nameptr[i];
  94.   FileName[j] = '\0';
  95.  
  96.   return 1;                 /* and return TRUE to keep going        */
  97. }
  98.  
  99. void Put_Msg ( char *msg )  /* replaces printf()                    */
  100. #ifdef INT29
  101.     /* gratuitous use of undocumented DOS */
  102.     while (*msg)
  103.     { _AL = *msg++;             /* MOV AL,*msg  */
  104.       geninterrupt(0x29);       /* INT 29h */
  105.     }
  106. #else
  107.     _AH = 2;    /* doesn't need to be inside loop */
  108.     while (*msg)
  109.     { _DL = *msg++;            
  110.       geninterrupt(0x21);
  111.     }
  112. #endif
  113. }
  114.  
  115. void Err_Halt ( char *msg )     /* print message and abort          */
  116. { Put_Msg ( msg );
  117.   Put_Msg ( "\r\n" );           /* send CR,LF   */
  118.   abort();
  119. }
  120.  
  121. void Move_Loader ( void )       /* vacate lower part of RAM         */
  122. {
  123.     unsigned movsize, destseg;
  124.     movsize = _heaptop - _psp; /* size of loader in paragraphs      */
  125.     destseg = *(unsigned far *)MK_FP( _psp, 2 ); /* end of memory   */
  126.     movup ( MK_FP( _psp, 0 ), MK_FP( destseg - movsize, 0 ),
  127.             movsize << 4);      /* move and fix segregs             */
  128. }
  129.  
  130. void Load_Drvr ( void )         /* load driver file into RAM    */
  131. { unsigned handle;
  132.   struct {
  133.     unsigned LoadSeg;
  134.     unsigned RelocSeg;
  135.   } ExecBlock;
  136.  
  137.   ExecBlock.LoadSeg = _psp + 0x10;
  138.   ExecBlock.RelocSeg = _psp + 0x10;
  139.   _DX = (unsigned)&FileName[0];
  140.   _BX = (unsigned)&ExecBlock;
  141.   _ES = _SS;                    /* es:bx point to ExecBlock     */
  142.   _AX = 0x4B03;                 /* load overlay                 */
  143.   geninterrupt ( 0x21 );        /* DS is okay on this call      */
  144.   GETFLAGS;
  145.   if ( _AH & 1 )
  146.     Err_Halt ( "Unable to load driver file." );
  147. }
  148.  
  149. void Get_List ( void )          /* set up pointers via List     */
  150. { _AH = 0x52;                   /* find DOS List of Lists       */
  151.   geninterrupt ( 0x21 );
  152.   nulseg = _ES;                 /* DOS data segment             */
  153.   LoLofs = _BX;                 /* current drive table offset   */
  154.  
  155.   switch( _osmajor )            /* NUL adr varies with version  */
  156.     {
  157.     case  0:
  158.       Err_Halt ( "Drivers not used in DOS V1." );
  159.     case  2:
  160.       nblkdrs = NULL;
  161.       nulofs = LoLofs + 0x17;
  162.       break;
  163.     case  3:
  164.       if (_osminor == 0)
  165.       {
  166.           nblkdrs = (BYTE far *) MK_FP(nulseg, LoLofs + 0x10);
  167.           lastdrive = *((BYTE far *) MK_FP(nulseg, LoLofs + 0x1b));
  168.           nulofs = LoLofs + 0x28;
  169.       }
  170.       else
  171.       {
  172.           nblkdrs = (BYTE far *) MK_FP(nulseg, LoLofs + 0x20);
  173.           lastdrive = *((BYTE far *) MK_FP(nulseg, LoLofs + 0x21));
  174.           nulofs = LoLofs + 0x22;
  175.       }
  176.       CDSbase = *(BYTE far * far *)MK_FP(nulseg, LoLofs + 0x16);
  177.       CDSsize = 81;
  178.       break;
  179.     case  4:
  180.     case  5:
  181.       nblkdrs = (BYTE far *) MK_FP(nulseg, LoLofs + 0x20);
  182.       lastdrive = *((BYTE far *) MK_FP(nulseg, LoLofs + 0x21));
  183.       nulofs  = LoLofs + 0x22;
  184.       CDSbase = *(BYTE far * far *) MK_FP(nulseg, LoLofs + 0x16);
  185.       CDSsize = 88;
  186.       break;
  187.     case 10:
  188.     case 20:
  189.       Err_Halt ( "OS2 DOS Box not supported." );
  190.     default:
  191.       Err_Halt ( "Unknown version of DOS!");
  192.     }
  193. }
  194.  
  195. void Fix_DOS_Chain ( void )     /* patches driver into DOS chn  */
  196. { unsigned i;
  197.  
  198.   nuldrvr = MK_FP( nulseg, nulofs+0x0A ); /* verify the drvr    */
  199.   drvptr = "NUL     ";
  200.   for ( i=0; i<8; ++i )
  201.     if ( *((BYTE far *)nuldrvr+i) != *((BYTE far *)drvptr+i) )
  202.       Err_Halt ( "Failed to find NUL driver." );
  203.  
  204.   nuldrvr = MK_FP( nulseg, nulofs );    /* point to NUL driver  */
  205.   drvptr  = MK_FP( _psp+0x10, 0 );      /* new driver's address */
  206.  
  207.   copyptr ( nuldrvr, &nxtdrvr );        /* hold old head now    */
  208.   copyptr ( &drvptr, nuldrvr );         /* put new after NUL    */
  209.   copyptr ( &nxtdrvr, drvptr );         /* and old after new    */
  210. }
  211.  
  212. // returns number of next free drive, -1 if none available
  213. int Next_Drive ( void )
  214. {
  215. #ifdef USE_BLKDEV
  216.   return (nblkdrs && (*nblkdrs < lastdrive)) ? *nblkdrs : -1;
  217. #else
  218.   /* The following approach takes account of SUBSTed and
  219.      network-redirector drives */
  220.   CDS far *cds;
  221.   int i;
  222.   /* find first unused entry in CDS structure */
  223.   for (i=0, cds=CDSbase; i<lastdrive; i++, ((BYTE far *)cds)+=CDSsize)
  224.     if (! cds->flags)                /* found a free drive  */
  225.         break;
  226.   return (i == lastdrive) ? -1 : i; 
  227. #endif  
  228. }
  229.  
  230. int Init_Drvr (